"""
OutputStreams.py -- defines custom outputs for debugging, warnings, ...

Contains a class OutputStream, which allows to define an output level
above which a message is printed.
"""

##@package OutputStreams
# Contains a class OutputStream, which allows to define an output
# level above which a message is printed.
#
# @author Johan "Solo" Luisier
# @date November 2011

## Class that implement the "output stream", providing 7 output levels
# : None, Verbose, Debug, Info, Warning, Error and Fatal.
#
# The instance has a tunable reference level: if the wanted output has
# a level greater or equal to the reference, the output is printed. In
# case the wanted output has a too low level, nothing is printed.
#
# The instance also has tunable decorators (i.e. colours for the font
# and the background, attributes) based on ANSI colour codes.
#
# @author Johan "Solo" Luisier
# @date November 2011
class OutputStream:
    ## Constructor
    # Initialises the instance, the levels are defined and the current
    # one set to 'Info'. Decorators are set to some reasonable values.
    #
    # @param[in] self reference on the calling instance.
    # @param[in] level reference level of the current instance.
    def __init__( self, level=3 ) :
        ## Stores the list of existing level names, indexed by the
        # level (number in \f$\left[0,6\right]\f$ interval.
        self.__ListOfLevels = { 0 : 'None',
                                1 : 'Verbose',
                                2 : 'Debug',
                                3 : 'Info',
                                4 : 'Warning',
                                5 : 'Error',
                                6 : 'Fatal'
                                }
        ## Stores the list of decorators, which are character strings
        # printed \e before the message, and alters the shell
        # rendering.
        self.__ListOfDecorators = { 0 : '',
                                    1 : '\033[0;32m',
                                    2 : '\033[0;34m',
                                    3 : '',
                                    4 : '\033[0;31m',
                                    5 : '\033[0;37;41m',
                                    6 : '\033[0;37;41;1m'
                                    }
        ## Stores the colour code for each colour, indexed by the
        # colour name. The foreground colour is obtained by adding 30
        # to the number, whilst the backgroundground colour is 40 plus
        # the same number.
        self.__ListOfColours = { 'Black'   : 0,
                                 'Red'     : 1,
                                 'Green'   : 2,
                                 'Yellow'  : 3,
                                 'Blue'    : 4,
                                 'Pink'    : 5,
                                 'Cyan'    : 6,
                                 'White'   : 7,
                                 'Default' : 8
                                 }
        # Stores the attribute number indexed by the attribute names.
        self.__ListOfAttributes = { 'None'          : 0,
                                    'Bold'          : 1,
                                    'Italic'        : 3,
                                    'Underline'     : 4,
                                    'Blink'         : 6,
                                    'Reverse'       : 7,
                                    'Concealed'     : 8,
                                    'Strikethrough' : 9
                                    }
        if ( level < 0 ) : level = 0
        if ( level > 6 ) : level = 6
        ## Stores the reference output level of the instance
        self.__Level = level
    ## Allows to print the output with the correct decorators.
    # If the wanted output level is greater or equal to the instance
    # reference level, then the string is actually printed to the
    # screen, with the corresponding decorator and the level name
    # appearing at the beginning of the line.
    #
    # @param[in] self reference on the calling instance.
    # @param[in] level wanted output level.
    # @param[in] string what will be printed.
    def doOutput( self, level, string ) :
        if ( level < 0 ) : level = 0
        if ( level > 6 ) : level = 6
        if ( self.__Level <= level ) :
            line = self.__ListOfDecorators[ level ]
            line += '{:<10}'.format(self.__ListOfLevels[level])
            line += string
            line += '\033[0;8;8;0m'
            print line
    ## Allows to change the output level of the instance.
    #
    # @param[in] self reference on the calling instance.
    # @param[in] level new value of __Level.
    #
    # @return the value of __Level
    def setOutputLevel( self, level ) :
        self.__Level = level
        return self.__Level
    ## Allows to access the value of __Level.
    #
    # @param[in] self reference on the calling instance.
    #
    # @return the value of __Level
    def getOuputLevel( self ) :
        return self.__Level
    ## Allows to change the decorator for a given output level.
    #
    # @param[in] self reference on the calling instance.
    # @param[in] level level for which the new decorator will be
    # created.
    # @param[in] colourFG foreground colour.
    # @param[in] colourBG background colour.
    # @param[in] attribute attribute (i.e, bold, italic, ...).
    #
    # @return the colour code.
    def setDecorator( self, level, colourFG='Default', colourBG='Default', attribute='None' ) :
        if ( level < 0 ) : level = 0
        if ( level > 6 ) : level = 6
        result = '\033[0;'
        result += str( self.__ListOfColours[ colourFG ] + 30 )
        result += ';'
        result += str( self.__ListOfColours[ colourBG ] + 40 )
        result += ';'
        result += str( self.__ListOfAttributes[ attribute ] )
        result += 'm'
        self.__ListOfDecorators[ level ] = result
        return result
    ## Alias to get better access to verbose output.
    #
    # @param[in] self reference on the calling instance.
    # @param[in] string what will be printed.
    def verbose( self, string ) :
        self.doOutput( 1, string )
    ## Alias to get better access to debug output.
    #
    # @param[in] self reference on the calling instance.
    # @param[in] string what will be printed.
    def debug( self, string ) :
        self.doOutput( 2, string )
    ## Alias to get better access to info output.
    #
    # @param[in] self reference on the calling instance.
    # @param[in] string what will be printed.
    def info( self, string ) :
        self.doOutput( 3, string )
    ## Alias to get better access to warning output.
    #
    # @param[in] self reference on the calling instance.
    # @param[in] string what will be printed.
    def warning( self, string ) :
        self.doOutput( 4, string )
    ## Alias to get better access to error output.
    #
    # @param[in] self reference on the calling instance.
    # @param[in] string what will be printed.
    def error( self, string ) :
        self.doOutput( 5, string )
    ## Alias to get better access to fatal output.
    #
    # @param[in] self reference on the calling instance.
    # @param[in] string what will be printed.
    def fatal( self, string ) :
        self.doOutput( 6, string )
